#include <gtest/gtest.h>

#include "util/char-input-stream.h"


TEST(char_input_stream, StrViewCharInputStream) {
    {
        std::string_view v;
        StrViewCharInputStream s(v);
        ASSERT_FALSE(s.hasNext());
    }

    {
        std::string_view v("a");
        StrViewCharInputStream s(v);
        ASSERT_TRUE(s.hasNext());
        ASSERT_EQ(s.next(), 'a');
    }

    {
        std::string_view v("abc");
        StrViewCharInputStream s(v);
        ASSERT_TRUE(s.hasNext());
        ASSERT_EQ(s.next(), 'a');
        ASSERT_TRUE(s.hasNext());
        ASSERT_EQ(s.next(), 'b');
        ASSERT_TRUE(s.hasNext());
        ASSERT_EQ(s.next(), 'c');
        ASSERT_FALSE(s.hasNext());
    }
}


// 检查是否有更多字符时都连续调用多次，以测试连续调用是否会使状态错误
TEST(char_input_stream, UnescapeCharInputStream) {
    {
        std::string_view v;
        StrViewCharInputStream s(v);
        UnescapeCharInputStream u(s);
        ASSERT_FALSE(u.hasNext());
        ASSERT_FALSE(u.hasNext());
    }

    {
        std::string_view v("a");
        StrViewCharInputStream s(v);
        UnescapeCharInputStream u(s);
        ASSERT_TRUE(u.hasNext());
        ASSERT_TRUE(u.hasNext());
        ASSERT_EQ(u.next(), 'a');
        ASSERT_FALSE(u.hasNext());
        ASSERT_FALSE(u.hasNext());
    }

    {
        std::string_view v("abc");
        StrViewCharInputStream s(v);
        UnescapeCharInputStream u(s);
        ASSERT_TRUE(u.hasNext());
        ASSERT_TRUE(u.hasNext());
        ASSERT_EQ(u.next(), 'a');
        ASSERT_TRUE(u.hasNext());
        ASSERT_TRUE(u.hasNext());
        ASSERT_EQ(u.next(), 'b');
        ASSERT_TRUE(u.hasNext());
        ASSERT_TRUE(u.hasNext());
        ASSERT_EQ(u.next(), 'c');
        ASSERT_FALSE(u.hasNext());
        ASSERT_FALSE(u.hasNext());
    }

    {
        // 只有一个转义字符时则认为没有字符，因为没有可以被转义的字符
        std::string_view v(R"(\)");
        StrViewCharInputStream s(v);
        UnescapeCharInputStream u(s);
        ASSERT_FALSE(u.hasNext());
        ASSERT_FALSE(u.hasNext());
    }

    {
        std::string_view v(R"(\\)");
        StrViewCharInputStream s(v);
        UnescapeCharInputStream u(s);
        ASSERT_TRUE(u.hasNext());
        ASSERT_TRUE(u.hasNext());
        ASSERT_EQ(u.next(), '\\');
        ASSERT_FALSE(u.hasNext());
        ASSERT_FALSE(u.hasNext());
    }

    {
        std::string_view v(R"(a\b\c)");
        StrViewCharInputStream s(v);
        UnescapeCharInputStream u(s);
        ASSERT_TRUE(u.hasNext());
        ASSERT_TRUE(u.hasNext());
        ASSERT_EQ(u.next(), 'a');
        ASSERT_TRUE(u.hasNext());
        ASSERT_TRUE(u.hasNext());
        ASSERT_EQ(u.next(), 'b');
        ASSERT_TRUE(u.hasNext());
        ASSERT_TRUE(u.hasNext());
        ASSERT_EQ(u.next(), 'c');
        ASSERT_FALSE(u.hasNext());
        ASSERT_FALSE(u.hasNext());
    }

    {
        std::string_view v(R"(a\bc)");
        StrViewCharInputStream s(v);
        UnescapeCharInputStream u(s);
        ASSERT_TRUE(u.hasNext());
        ASSERT_TRUE(u.hasNext());
        ASSERT_EQ(u.next(), 'a');
        ASSERT_TRUE(u.hasNext());
        ASSERT_TRUE(u.hasNext());
        ASSERT_EQ(u.next(), 'b');
        ASSERT_TRUE(u.hasNext());
        ASSERT_TRUE(u.hasNext());
        ASSERT_EQ(u.next(), 'c');
        ASSERT_FALSE(u.hasNext());
        ASSERT_FALSE(u.hasNext());
    }

    {
        std::string_view v(R"(a\bc\)");
        StrViewCharInputStream s(v);
        UnescapeCharInputStream u(s);
        ASSERT_TRUE(u.hasNext());
        ASSERT_TRUE(u.hasNext());
        ASSERT_EQ(u.next(), 'a');
        ASSERT_TRUE(u.hasNext());
        ASSERT_TRUE(u.hasNext());
        ASSERT_EQ(u.next(), 'b');
        ASSERT_TRUE(u.hasNext());
        ASSERT_TRUE(u.hasNext());
        ASSERT_EQ(u.next(), 'c');
        ASSERT_FALSE(u.hasNext());
        ASSERT_FALSE(u.hasNext());
    }
}
